/** /////////////////////////////////////////////////////////////////////////////////
 * @author	Jaeger, Mathias
 * @class 	fahrzeug.js dient zum Einladen und Zusammenfügen von Fahrzeuggeometrien
 * 			und implementiert eine einfache antrieb. Zum Wechseln der Geometrien
 * 			muessen die globalen Variablen auf die Dateien entsprechen aktualisiert
 * 			werden. Abstaende und Positionierung entsprechend neuer Geometrie.
 *
 *//////////////////////////////////////////////////////////////////////////////////
fahrzeug = function() {

	// Verweis auf das JSON-File fuer die Raeder
	var radURL = "assets/models/rad_2.js";
	// Verweis auf das JSON-File fuer die Karosserie
	var karosserieURL = "assets/models/karosserie_3.js";

	var rad_meshes = [4];

	var bremsLichtLinks;
	var bremsLichtRechts;

	radLaden();

	/** Funktion um ein Rad mit Physijs-Einsatz an uebergebener Position zu erzeugen.
	 * Wobei das Mesh selbst keine physikalischen Eigenschaften bekommt. Diese werden
	 * ueber ein unsichtbares CylinderMesh simuliert um Performance zu spareb
	 *
	 * @param postion 		Positions-Vector an die das Rad muss
	 * @param radNummer		Integerwert fuer rad_meshes-Array:
	 * 						0 - Hinten-Rechts
	 * 						1 -	Hinten-Links
	 * 						2 - Vorne-Rechts
	 * 						3 - Vorne-Links
	 */
	function radColliderMeshErstellen(position, radNummer) {
		// Three.js-Materialien aus MatLibThree.js laden und Physijs ergaenzen
		var radCollider_material = Physijs.createMaterial(lTransparentT, 2.0, 1.0);
		var radCollider_geometry = new THREE.CylinderGeometry(1.8, 1.8, 1, 0);
		// Rad-Mesh durch Verbindung von Geometrie und Materialien erzeugen und Masse zuweisen
		var radCollider_mesh = new Physijs.SphereMesh(radCollider_geometry, radCollider_material, 1);
		// Schattenwurf aktivieren
		radCollider_mesh.castShadow = true;
		radCollider_mesh.rotation.x = Math.PI / 2;
		// Rad-Positionierung durch uebergebenen Parameter
		radCollider_mesh.position = position;
		radCollider_mesh.radNummer = radNummer;
		radCollider_mesh.add(rad_meshes[radNummer]);

		return radCollider_mesh;
	}

	/**
	 * Laden der Geometrie des Rades und mehrfaches abspeichern im Array
	 * Abschliessend wird karosserieLaden() aufgerufen
	 */
	function radLaden() {

		// materialien wieder einfuegen
		laneAssist.loader.load(radURL, function(geometrie, mat) {
			var radMaterialien = new THREE.MeshFaceMaterial(mat);
			radMaterialien.materials[0] = pChromeT;
			radMaterialien.materials[1] = lBlackT;

			for (var i = 0; i < 4; i++) {
				rad_mesh = new THREE.Mesh(geometrie, radMaterialien);
				if (i == 1 || i == 3) {
					rad_mesh.rotation.y = Math.PI / 2;
					rad_mesh.rotation.x = -Math.PI / 2;
					rad_meshes[i] = rad_mesh;
				} else {

					rad_mesh.rotation.y = Math.PI / 2;
					rad_mesh.rotation.x = Math.PI / 2;
					rad_meshes[i] = rad_mesh;
				}
			}
			karosserieLaden();
		});
	}

	/**
	 * Laden der Karosseriedaten.
	 * Abschliessend wird setup() aufgerufen um die Einzelteile zusammenzufuehren.
	 */
	function karosserieLaden() {

		karosserieDummy = new Physijs.BoxMesh(new THREE.CubeGeometry(15, 5, 5), lTransparentT, 100);
		karosserieDummy.position.set(0, 6, +fahrbahnBreite / 4);

		// Referenz auf Datei und Callback-Funktion
		laneAssist.loader.load(karosserieURL, function(geometry, mat) {
			var materials = new THREE.MeshFaceMaterial(mat);
			
			materials.materials[0] = pBlackGlasT;
			materials.materials[1] = pBlackT;
			materials.materials[2] = pSilverBlueCarPaintT;
			materials.materials[3] = pChromeT;
			materials.materials[4] = lDarkGreyT;
			materials.materials[5] = lBlueT;
			materials.materials[7] = lBlueT;
			materials.materials[7] = lBlueT;
			materials.materials[9] = lBlueT;
			materials.materials[10] = lBlueT;
			materials.materials[11] = lBlueT;
			materials.materials[12] = lBlueT;

			karosserie = new THREE.Mesh(geometry, materials);
			
			// Schattenwurf aktivieren
			karosserie.castShadow = true;
			karosserie.receiveShadow = true;

			// Eventlistener an Trigger binden
			karosserieDummy.addEventListener('collision', function(kollisionsObjekt, kollisionsWucht, relative_rotation, contact_normal) {
				if (kollisionsObjekt.trigger == "Mitte") {
					spurwechsel = false;
					zuNullLenken();
				}
				if (kollisionsObjekt.trigger == "Seite") {
					spurwechsel = true;
					zuNullLenken();
				}
			});

			karosserieDummy.add(karosserie);

			var bremsLichtTextur = THREE.ImageUtils.loadTexture("assets/textures/lensflare/lensflare0_alpha.png", undefined, erstelleBremslichter);
			var blinkLichtTextur = THREE.ImageUtils.loadTexture("assets/textures/lensflare/lensflare0_alpha.png", undefined, erstelleBlinklichter);

			var unterboden = new THREE.Mesh(new THREE.PlaneGeometry(24, 10, 1),lTransparentT);
			unterboden.position.y -=2;
			unterboden.rotation.x = Math.PI / 2;
			unterboden.castShadow = true;
			karosserieDummy.add(unterboden);

			szene.add(karosserieDummy);
			setup();
		});

	}

	/**
	 * setup() führt die Einzelteile zusammen und implementiert die Fahrzeugmotor.
	 *
	 * Abschliessend findet der Aufruf von requestAnimationFrame statt!!!
	 */
	function setup() {
		/*Einzelteile (Materialien und Geometrien einladen)*/
		// Three.js-Materialien aus MatLibThree.js laden

		// Raeder an Parameterposition erzeugen und in Szene einfuegen
		var radHintenLinks_Positioniert = radColliderMeshErstellen(new THREE.Vector3(-7, 4, 4.5 + fahrbahnBreite / 4), 0);
		szene.add(radHintenLinks_Positioniert);
		var radHintenRechts_Positioniert = radColliderMeshErstellen(new THREE.Vector3(-7, 4, -4.5 + fahrbahnBreite / 4), 1);
		szene.add(radHintenRechts_Positioniert);
		var radVorneLinks_Positioniert = radColliderMeshErstellen(new THREE.Vector3(8, 4, 4.75 + fahrbahnBreite / 4), 2);
		szene.add(radVorneLinks_Positioniert);
		var radVorneRechts_Positioniert = radColliderMeshErstellen(new THREE.Vector3(8, 4, -4.75 + fahrbahnBreite / 4), 3);
		szene.add(radVorneRechts_Positioniert);

		// Constraints erzeugen und in Szene einfuegen
		var radHintenLinks_Fixiert = fixieren(radHintenLinks_Positioniert, karosserieDummy, new THREE.Vector3(-7, 4, 4.5 + fahrbahnBreite / 4));
		szene.addConstraint(radHintenLinks_Fixiert);
		var radHintenRechts_Fixiert = fixieren(radHintenRechts_Positioniert, karosserieDummy, new THREE.Vector3(-7, 4, -4.5 + fahrbahnBreite / 4));
		szene.addConstraint(radHintenRechts_Fixiert);
		var radVorneLinks_Fixiert = fixieren(radVorneLinks_Positioniert, karosserieDummy, new THREE.Vector3(8, 4, 4.5 + fahrbahnBreite / 4));
		szene.addConstraint(radVorneLinks_Fixiert);
		var radVorneRechts_Fixiert = fixieren(radVorneRechts_Positioniert, karosserieDummy, new THREE.Vector3(8, 4, -4.5 + fahrbahnBreite / 4));
		szene.addConstraint(radVorneRechts_Fixiert);

		/* Die Vorderreifen werden in X und Y beschraenkt.
		 * Nur eine Drehung um Z soll moeglich sein.
		 * Eine groesserer Wert im Unteren Limit als im Oberen, hebt das Limit auf.
		 * Identische Werte in beiden Limits fixieren die Position.*/
		radVorneLinks_Fixiert.setAngularLowerLimit({
			x : 0,
			y : 0,
			z : 0.1
		});
		radVorneLinks_Fixiert.setAngularUpperLimit({
			x : 0,
			y : 0,
			z : 0
		});
		radVorneRechts_Fixiert.setAngularLowerLimit({
			x : 0,
			y : 0,
			z : 0.1
		});
		radVorneRechts_Fixiert.setAngularUpperLimit({
			x : 0,
			y : 0,
			z : 0
		});

		/* Die Hinterreifen werden zunaechst in XYZ fixiert.
		 * Z wird zwar zur Drehung benoetigt, doch ueberschreibt der
		 * im Anschluss konfiguerierte antrieb einen Wert nach Bedarf.*/
		radHintenLinks_Fixiert.setAngularLowerLimit({
			x : 0,
			y : 0,
			z : 1
		});
		radHintenLinks_Fixiert.setAngularUpperLimit({
			x : 0,
			y : 0,
			z : 0
		});
		radHintenRechts_Fixiert.setAngularLowerLimit({
			x : 0,
			y : 0,
			z : 0
		});
		radHintenRechts_Fixiert.setAngularUpperLimit({
			x : 0,
			y : 0,
			z : 0
		});

		// Antrieb an Hinterraedern durch antrieb an Y-Achse
		radHintenRechts_Fixiert.configureAngularMotor(2, 0.1, 0, 0, 0);
		radHintenLinks_Fixiert.configureAngularMotor(2, 0.1, 0, 0, 0);

		// NEU NEU NEU
		radVorneRechts_Fixiert.configureAngularMotor(2, 0.1, 0, 0, 0);
		radVorneLinks_Fixiert.configureAngularMotor(2, 0.1, 0, 0, 0);

		// Constraints in neue entsprechende Variablen des Fahrzeugs uebergeben
		fahrzeug.radHintenRechts_Fixiert = radHintenRechts_Fixiert;
		fahrzeug.radHintenLinks_Fixiert = radHintenLinks_Fixiert;
		fahrzeug.radVorneRechts_Fixiert = radVorneRechts_Fixiert;
		fahrzeug.radVorneLinks_Fixiert = radVorneLinks_Fixiert;

		// Karosserie in neue entsprechende Variable des Fahrzeugs uebergeben
		fahrzeug.karosserie = karosserie;

		antrieb = new function () {
		this.geschwindigkeit = laneAssist.fahrzeug.geschwindigkeit;
		this.radEinschlag = laneAssist.fahrzeug.radEinschlag;
		this.loosenXRight = 0.0001;
		this.loosenXLeft = 0.0001;

		this.aktualisiereGeschwindigkeit = function () {
		// if you add a antrieb, the current constraint is overridden
		// if you want to rotate set min higher then max
		fahrzeug.radHintenRechts_Fixiert.configureAngularMotor(2, 0.1, 0, laneAssist.fahrzeug.geschwindigkeit, 5);
		fahrzeug.radHintenLinks_Fixiert.configureAngularMotor(2, 0.1, 0, laneAssist.fahrzeug.geschwindigkeit, 5);

		// NEU NEU NEU
		fahrzeug.radVorneRechts_Fixiert.configureAngularMotor(2, 0.1, 0, laneAssist.fahrzeug.geschwindigkeit, 20);
		fahrzeug.radVorneLinks_Fixiert.configureAngularMotor(2, 0.1, 0, laneAssist.fahrzeug.geschwindigkeit, 20);

		// antrieb two is forward and backwards
		fahrzeug.radHintenRechts_Fixiert.enableAngularMotor(2);
		fahrzeug.radHintenLinks_Fixiert.enableAngularMotor(2);
		fahrzeug.radVorneRechts_Fixiert.enableAngularMotor(2);
		fahrzeug.radVorneLinks_Fixiert.enableAngularMotor(2);
		};

		this.aktualisiereRadEinschlag = function () {
		fahrzeug.radVorneLinks_Fixiert.setAngularLowerLimit({ x: 0, y: laneAssist.fahrzeug.radEinschlag, z: 0.1 });
		fahrzeug.radVorneLinks_Fixiert.setAngularUpperLimit({ x: antrieb.loosenXRight, y: laneAssist.fahrzeug.radEinschlag, z: 0 });
		fahrzeug.radVorneRechts_Fixiert.setAngularLowerLimit({ x: antrieb.loosenXLeft, y: laneAssist.fahrzeug.radEinschlag, z: 0.1 });
		fahrzeug.radVorneRechts_Fixiert.setAngularUpperLimit({ x: 0, y: laneAssist.fahrzeug.radEinschlag, z: 0 });
		};

		};

		var folderAntrieb = laneAssist.gui.addFolder("Antrieb");
		var AntriebGeschwindigkeit = folderAntrieb.add(laneAssist.fahrzeug, "geschwindigkeit").min(-120).max(-00).step(1).listen();
		var AntriebRadEinschlag = folderAntrieb.add(laneAssist.fahrzeug, "radEinschlag").min(-1).max(1).step(.0001).listen();
		
		AntriebGeschwindigkeit.onChange(function(value){			
			laneAssist.fahrzeug.geschwindigkeit = -value;
			document.getElementById("geschwindigkeit").innerText = value + "Km/h";

		});
		
		AntriebRadEinschlag.onChange(function(value){			
			laneAssist.fahrzeug.radEinschlag = value;
		});
		
		
		//laneAssist.gui.add(antrieb, 'geschwindigkeit', 0, -150).onChange(antrieb.aktualisiereGeschwindigkeit);
		//laneAssist.gui.add(antrieb, 'radEinschlag', -1.000, 1.000).onChange(antrieb.aktualisiereRadEinschlag);

		antrieb.loosenXLeft = 0;
		antrieb.loosenXRight = 0;
		//laneAssist.fahrzeug.geschwindigkeit = -60;

		requestAnimationFrame(render);

	}

	/** Funktion die das Rad (1.) an der Karosserie (2.) an Position (3.) fixiert
	 *
	 * @param {Object} was		Was soll fixiert werden?
	 * @param {Object} woran	Woran soll was fixiert werden?
	 * @param {Object} wo		Wo am Woran soll was fixirt werden?
	 */
	function fixieren(was, woran, wo) {
		// "Degree of Freedom"-Constraint erlaubt die Beschraenkung der Rotation
		var fixiertesRad = new Physijs.DOFConstraint(was, woran, wo);

		return fixiertesRad;
	}

	function erstelleBremslichter(texture) {

		var material = new THREE.SpriteMaterial({
			color : 0xff0000,
			blending : THREE.AdditiveAlphaBlending,
			map : texture,
			opacity : 0.25,
			useScreenCoordinates : false,
			transparent : true,
			// alphaTest : 0.1
		});

		var breite = material.map.image.width * 0.02;
		var hoehe = material.map.image.height * 0.02;

		bremsLichtLinks = new THREE.Sprite(material);
		bremsLichtRechts = new THREE.Sprite(material);
		bremsLichtLinks.scale.set(breite, hoehe, 1);
		bremsLichtRechts.scale.set(breite, hoehe, 1);

		bremsLichtLinks.position.set(-14, 1.25, -3);
		bremsLichtRechts.position.set(-14, 1.25, 3);
		karosserieDummy.add(bremsLichtLinks);
		karosserieDummy.add(bremsLichtRechts);
	};

	function erstelleBlinklichter(texture) {

		var materialRechts = new THREE.SpriteMaterial({
			color : 0xffff00,
			blending : THREE.AdditiveBlending,
			map : texture,
			opacity : 0,
			useScreenCoordinates : false,
			transparent : true,
			// alphaTest : 0.1,
			//visible : false
		});
		
				var materialLinks = new THREE.SpriteMaterial({
			color : 0xffff00,
			blending : THREE.AdditiveBlending,
			map : texture,
			opacity : 0,
			useScreenCoordinates : false,
			transparent : true,
			// alphaTest : 0.1
		});


		var breite = materialRechts.map.image.width * 0.01;
		var hoehe = materialRechts.map.image.height * 0.01;
		var breite = materialLinks.map.image.width * 0.01;
		var hoehe = materialLinks.map.image.height * 0.01;

		// Blinker an der Seitenspiegeln
		blinkerSeiteSprite_links = new THREE.Sprite(materialLinks);
		blinkerSeiteSprite_rechts = new THREE.Sprite(materialRechts);
		blinkerSeiteSprite_links.scale.set(breite, hoehe, 1);
		blinkerSeiteSprite_rechts.scale.set(breite, hoehe, 1);

		blinkerSeiteSprite_links.position.set(3.25, 1.75, -5.5);
		blinkerSeiteSprite_rechts.position.set(3.25, 1.75, 5.5);

		karosserieDummy.add(blinkerSeiteSprite_links);
		karosserieDummy.add(blinkerSeiteSprite_rechts);

		// Blinker an den Ruecklichtern
		blinkerHintenSprite_links = new THREE.Sprite(materialLinks);
		blinkerHintenSprite_rechts = new THREE.Sprite(materialRechts);
		blinkerHintenSprite_links.scale.set(breite, hoehe, 1);
		blinkerHintenSprite_rechts.scale.set(breite, hoehe, 1);

		blinkerHintenSprite_links.position.set(-12, 1, -3.5);
		blinkerHintenSprite_rechts.position.set(-12, 1, 3.5);
		
		karosserieDummy.add(blinkerHintenSprite_links);
		karosserieDummy.add(blinkerHintenSprite_rechts);

		// Blinker an den Vorderlichtern
		blinkerVorneSprite_links = new THREE.Sprite(materialLinks);
		blinkerVorneSprite_rechts = new THREE.Sprite(materialRechts);
		blinkerVorneSprite_links.scale.set(breite, hoehe, 1);
		blinkerVorneSprite_rechts.scale.set(breite, hoehe, 1);

		blinkerVorneSprite_links.position.set(11.75, 0, -4.25);
		blinkerVorneSprite_rechts.position.set(11.75, 0, 4.25);
		
		karosserieDummy.add(blinkerVorneSprite_links);
		karosserieDummy.add(blinkerVorneSprite_rechts);
		
		blinkerVorneSprite_rechts.visible = false;
		blinkerSeiteSprite_rechts.visible = false;
		blinkerHintenSprite_rechts.visible = false;
		
		blinkerVorneSprite_links.visible = false;
		blinkerSeiteSprite_links.visible = false;
		blinkerHintenSprite_links.visible = false;
		
		// Blinkeranimation starten
		updateBlinklicht();
	};

	function updateBlinklicht() {
		//var material = spriteTL.material;
		var aktuell = {
			opacity : blinkerSeiteSprite_rechts.opacity
		};

		var an = {
			opacity : 1
		};

		var aus = {
			opacity : 0
		};

		tweenZuAn = new TWEEN.Tween(aktuell).to(an, 500);
		tweenZuAus = new TWEEN.Tween(aktuell).to(aus, 500);

		tweenZuAn.onUpdate(function() {
			blinkerSeiteSprite_rechts.material.opacity = aktuell.opacity;
			blinkerSeiteSprite_links.material.opacity = aktuell.opacity;
		});
		
		tweenZuAus.onUpdate(function() {
			blinkerSeiteSprite_rechts.material.opacity = aktuell.opacity;
			blinkerSeiteSprite_links.material.opacity = aktuell.opacity;
		});

		tweenZuAn.chain(tweenZuAus);
		tweenZuAus.chain(tweenZuAn);

		tweenZuAn.start();

	};

};
